package com.bfly.mall.tasks;

import com.bfly.common.util.DateUtil;
import com.bfly.core.cache.SysConfigCacheUtil;
import com.bfly.core.context.CacheableThreadLocal;
import com.bfly.core.context.event.ScheduledTaskExecCompleteEvent;
import com.bfly.core.enums.AccessRole;
import com.bfly.core.security.ScheduledInfo;
import com.bfly.mall.order.entity.Order;
import com.bfly.mall.order.entity.OrderLogs;
import com.bfly.mall.order.entity.OrderRefund;
import com.bfly.mall.order.enums.*;
import com.bfly.mall.order.event.OrderRefundEvent;
import com.bfly.mall.order.service.IOrderLogsService;
import com.bfly.mall.order.service.IOrderRefundService;
import com.bfly.mall.order.service.IOrderService;
import com.bfly.mall.system.dto.OrderConfigDTO;
import com.bfly.mall.tasks.entity.ScheduledTaskExecResult;
import com.bfly.mall.tasks.service.IScheduled;
import com.bfly.mall.wechat.minipro.dto.WeChatOrderQueryResponse;
import com.bfly.mall.wechat.minipro.dto.WeChatRefundOrderQueryResponse;
import com.bfly.mall.wechat.minipro.service.WeChatMiniProOrderApi;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * 订单定时任务
 *
 * @author 长沙商脉科技有限公司
 * @date 2020/5/11 15:19
 */
@Component
public class OrderTask extends AbstractScheduledTask implements IScheduled {

    private Logger logger = LoggerFactory.getLogger(OrderTask.class);
    // 未支付订单检查 30秒周期
    private static final String UN_PAY_ORDER_CHECK = "un_pay_order_check";
    private static final String UN_PAY_ORDER_CHECK_CRON = "0/30 * * * * ?";

    // 订单自动收货检查 5分钟周期
    private static final String AUTO_RECEIVED_ORDER_CHECK = "auto_received_order_check";
    private static final String AUTO_RECEIVED_ORDER_CHECK_CRON = "0 0/5 * * * ?";

    // 订单退款状态检查 1分钟周期
    private static final String REFUND_ORDER_STATUS_CHECK = "refund_order_status_check";
    private static final String REFUND_ORDER_STATUS_CHECK_CRON = "0 0/1 * * * ?";

    @Autowired
    private IOrderService orderService;
    @Autowired
    private IOrderRefundService refundService;
    @Autowired
    private IOrderLogsService logsService;
    @Autowired
    private ApplicationContext applicationContext;

    /**
     * 每30秒执行一次，查询未支付的订单
     * 15分钟内没有支付完成的订单取消订单
     *
     * @author 长沙商脉科技有限公司
     * @date 2020/5/11 15:38
     */
    @Scheduled(cron = UN_PAY_ORDER_CHECK_CRON)
    @ScheduledInfo(name = UN_PAY_ORDER_CHECK, remark = "每30秒执行一次,指定时间内没有支付完成的订单则取消订单")
    public void unPayOrderCheck() {
        synchronized (this.getClass()) {
            if (!allowRun(UN_PAY_ORDER_CHECK)) {
                return;
            }
            OrderConfigDTO orderConfig = SysConfigCacheUtil.getOrderConfig();
            if (orderConfig.getAutoCancelTime() < 0) {
                logger.info("请配置订单支付超时时间!");
                return;
            }
            String message = "执行成功!";
            try {
                CacheableThreadLocal.set(false);
                Map<String, Object> param = new HashMap<>();
                param.put("order_status", OrderStatusEnum.OPEN.getId());
                param.put("pay_status", PayStatusEnum.WAIT_PAY.getId());
                param.put("express_status", ExpressStatusEnum.INITIAL.getId());
                param.put("create_date_endDate", new Date());        // 防止大数据查出造成负担 一次任务执行查询小于当前时间的订单
                param.put("is_deleted", false);
                List<Order> list = orderService.getList(param);
                list.forEach(order -> {
                    Date now = new Date();
                    Date expire = DateUtils.addSeconds(order.getCreateDate(), orderConfig.getAutoCancelTime());
                    if (now.after(expire)) {
                        // 支付超时取消订单
                        doPayExpireOrder(order);
                    } else {
                        // 查询微信服务器订单支付状态并修改
                        doPaySuccessOrder(order);
                    }
                });
            } catch (Exception e) {
                message = e.getMessage();
            } finally {
                CacheableThreadLocal.clear();
            }
            ScheduledTaskExecResult result = new ScheduledTaskExecResult(UN_PAY_ORDER_CHECK, UN_PAY_ORDER_CHECK_CRON, Calendar.getInstance().getTime(), message);
            executeCompletedEvent(new ScheduledTaskExecCompleteEvent(result));
        }
    }

    /**
     * 微信服务器查询订单并修改支付成功的订单支付状态
     *
     * @author 长沙商脉科技有限公司
     * @date 2020/5/11 19:09
     */
    private void doPaySuccessOrder(Order order) {
        try {
            WeChatOrderQueryResponse responseMsg = WeChatMiniProOrderApi.queryOrderFromWeChat(order.getOrderNo());
            if ("SUCCESS".equalsIgnoreCase(responseMsg.getTrade_state())) {
                // 支付成功  支付时间
                Date payTime = DateUtil.parse(responseMsg.getSuccess_time(), "yyyy-MM-dd'T'HH:mm:ssXXX");
                String transactionId = responseMsg.getTransaction_id();
                orderService.paySuccessOrder(order.getOrderNo(), transactionId, payTime, 0, "系统任务", OrderOpTypeEnum.PAY_MEMBER, AccessRole.SYSTEM);
            }
        } catch (Exception e) {
            logger.error(String.format("查询未支付订单[%s]状态异常", order.getOrderNo()), e);
            throw new RuntimeException("查询未支付订单状态异常:" + e.getMessage());
        }
    }

    /**
     * 处理支付超时订单
     *
     * @author 长沙商脉科技有限公司
     * @date 2020/5/11 19:08
     */
    private void doPayExpireOrder(Order order) {
        try {
            orderService.cancelOrder(order.getOrderNo(), "支付超时系统自动取消", 0, "系统任务", AccessRole.SYSTEM);
        } catch (Exception e) {
            logger.warn(String.format("取消支付超时订单[%s]出错", order.getOrderNo()), e);
            throw new RuntimeException("取消支付超时订单出错:" + e.getMessage());
        }
    }


    /**
     * 自动收货检查
     *
     * @author 长沙商脉科技有限公司
     * @date 2020/12/4 17:40
     */
    @Scheduled(cron = AUTO_RECEIVED_ORDER_CHECK_CRON)
    @ScheduledInfo(name = AUTO_RECEIVED_ORDER_CHECK, remark = "每5分钟执行一次,指定时间内没有确认收货的订单系统自动确认收货")
    public void autoReceivedCheck() {
        if (!allowRun(AUTO_RECEIVED_ORDER_CHECK)) {
            return;
        }
        OrderConfigDTO orderConfig = SysConfigCacheUtil.getOrderConfig();
        if (orderConfig.getAutoReceivedTime() < 0) {
            logger.info("请配置订单自动收货时间!");
            return;
        }
        CacheableThreadLocal.set(false);
        Map<String, Object> param = new HashMap<>();
        param.put("order_status", OrderStatusEnum.OPEN.getId());
        param.put("pay_status", PayStatusEnum.SUCCESS.getId());
        param.put("express_status", ExpressStatusEnum.SHIPPING.getId());
        param.put("create_date_endDate", new Date());        // 防止大数据查出造成负担 一次任务执行查询小于当前时间的订单
        param.put("is_deleted", false);

        String message = "执行成功!";
        try {
            List<Order> list = orderService.getList(param);
            list.forEach(order -> {
                Date now = new Date();
                Date expire = DateUtils.addDays(order.getCreateDate(), orderConfig.getAutoReceivedTime());
                if (now.after(expire)) {
                    // 收货超时系统自动收货
                    doAutoReceivedOrder(order);
                }
            });
        } catch (Exception e) {
            message = e.getMessage();
        } finally {
            CacheableThreadLocal.clear();
        }
        ScheduledTaskExecResult result = new ScheduledTaskExecResult(AUTO_RECEIVED_ORDER_CHECK, AUTO_RECEIVED_ORDER_CHECK_CRON, Calendar.getInstance().getTime(), message);
        executeCompletedEvent(new ScheduledTaskExecCompleteEvent(result));
    }

    /**
     * 处理自动收货
     *
     * @author 长沙商脉科技有限公司
     * @date 2020/12/4 18:01
     */
    private void doAutoReceivedOrder(Order order) {
        orderService.confirmReceiveOrder(order.getOrderNo(), "收货超时系统自动收货", 0, "系统任务", AccessRole.SYSTEM);
    }

    /**
     * 每30秒执行一次，查询退款状态的订单
     * 退款成功修改订单退款状态
     *
     * @author 长沙商脉科技有限公司
     * @date 2020/5/11 15:38
     */
    @Scheduled(cron = REFUND_ORDER_STATUS_CHECK_CRON)
    @ScheduledInfo(name = REFUND_ORDER_STATUS_CHECK, remark = "每1分钟执行一次查询订单退款状态")
    public void refundOrderStatusCheck() {
        synchronized (this.getClass()) {
            if (!allowRun(REFUND_ORDER_STATUS_CHECK)) {
                return;
            }
            String message = "执行成功!";
            try {
                CacheableThreadLocal.set(false);
                Map<String, Object> param = new HashMap<>();
                param.put("status", RefundStatusEnum.PASS.getId());
                param.put("progress_status", RefundProgressEnum.PROGRESSING.getId());
                param.put("create_date_endDate", new Date());        // 防止大数据查出造成负担 一次任务执行查询小于当前时间的订单
                List<OrderRefund> list = refundService.getList(param);
                list.forEach(refund -> {
                    try {
                        doQueryRefundOrder(refund);
                    } catch (Exception ex) {
                        logger.error(String.format("查询退款订单[%s]出错", refund.getRefundNo()), ex);
                    }
                });
            } catch (Exception e) {
                message = e.getMessage();
            } finally {
                CacheableThreadLocal.clear();
            }
            ScheduledTaskExecResult result = new ScheduledTaskExecResult(REFUND_ORDER_STATUS_CHECK, REFUND_ORDER_STATUS_CHECK_CRON, Calendar.getInstance().getTime(), message);
            executeCompletedEvent(new ScheduledTaskExecCompleteEvent(result));
        }
    }

    /**
     * 执行查询退款单操作
     *
     * @author 长沙商脉科技有限公司
     * @date 2020/12/11 14:25
     */
    private void doQueryRefundOrder(OrderRefund orderRefund) {
        WeChatRefundOrderQueryResponse response = WeChatMiniProOrderApi.queryRefundOrderStatusFromWeChat(orderRefund.getRefundId());
        String message = "";
        if ("SUCCESS".equalsIgnoreCase(response.getRefundStatus())) {
            //修改订单状态为已关闭 已退款
            orderService.editPayStatus(orderRefund.getOrderNo(), PayStatusEnum.REFUNDED);
            orderService.editOrderStatus(orderRefund.getOrderNo(), OrderStatusEnum.CLOSE);
            // 修改状态为退款成功
            refundService.editOrderRefundStatus(orderRefund.getRefundNo(), RefundProgressEnum.SUCCESS);
            message = "退款成功";

        } else if ("CHANGE".equalsIgnoreCase(response.getRefundStatus())) {
            // 修改状态为退款失败
            refundService.editOrderRefundStatus(orderRefund.getRefundNo(), RefundProgressEnum.FAIL);
            message = "退款失败";
        } else if ("CHANGE".equalsIgnoreCase(response.getRefundStatus())) {
            // 退款异常
            message = "退款异常,可前往商户平台交易中心手动处理此笔退款";
            refundService.editOrderRefundStatus(orderRefund.getRefundNo(), RefundProgressEnum.CLOSE);
        } else if ("REFUNDCLOSE".equalsIgnoreCase(response.getRefundStatus())) {
            message = "退款关闭";
            refundService.editOrderRefundStatus(orderRefund.getRefundNo(), RefundProgressEnum.CLOSE);
        } else {
            return;
        }

        logger.info(String.format(message + ":[%s,%s]", orderRefund.getRefundNo(), orderRefund.getOrderNo()));
        OrderLogs logs = new OrderLogs();
        logs.setOrderNo(orderRefund.getOrderNo());
        logs.setCreateDate(response.getRefundSuccessTime());
        logs.setType(OrderOpTypeEnum.REFUND_COMPLETE.getId());
        logs.setOperatorId(0);
        logs.setOperatorName("系统任务");
        logs.setRemark(message);
        logsService.save(logs);

        // 发送退款消息
        OrderRefundEvent event = new OrderRefundEvent(applicationContext, orderRefund.getOrderNo(), response.getRefundSuccessTime(), orderRefund.getRefundPrice());
        applicationContext.publishEvent(event);
    }
}
